package com.pai4j.pgc.service.aig;
import com.pai4j.common.bean.PAIPageResponseBeanUtil;
import com.pai4j.common.enums.community.*;
import com.pai4j.common.exception.BusinessException;
import com.pai4j.common.helper.SseEmitterHelper;
import com.pai4j.common.service.FreeMarkEngineService;
import com.pai4j.common.util.JsonUtil;
import com.pai4j.common.util.ListUtil;
import com.pai4j.domain.community.dto.ai.CCLLMChatRequestDTO;
import com.pai4j.pgc.pojo.es.CommunitySearchResultDTO;
import com.pai4j.domain.community.vo.DictConfigResponseVO;
import com.pai4j.domain.community.vo.response.cc.CCAgentRecommendResponseVO;
import com.pai4j.domain.community.vo.response.cc.CTCPathDetailVO;
import com.pai4j.domain.vo.llm.ChatCompletionMessage;
import com.pai4j.domain.vo.llm.ChatMessageRole;
import com.pai4j.pgc.controller.community.AibotSocket;
import com.pai4j.pgc.entity.community.CCAnswerEntity;
import com.pai4j.pgc.service.community.CCAnswerService;
import com.pai4j.pgc.service.community.CCPathService;
import com.pai4j.pgc.service.community.DictConfigService;
import com.pai4j.pgc.service.behavior.AbstractResourceBehaviorService;
import com.pai4j.pgc.service.behavior.ResourceBehaviorFactory;
import com.pai4j.common.listener.event.data.CommunityEventData;
import com.pai4j.pgc.service.es.CommunityElasticSearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Flux;

import java.io.IOException;
import java.util.*;

@Slf4j
@Service
public class CCAgentService {

    @Autowired
    private DeepSeekAIService deepSeekAIService;
    @Autowired
    private CCPathService pathService;
    @Autowired
    private FreeMarkEngineService freeMarkEngineService;
    @Autowired
    private CommunityElasticSearchService communityElasticSearchService;
    @Autowired
    private CCAnswerService answerService;
    @Autowired
    private DictConfigService dictConfigService;

    @Value("${cc.community.qaPageUrl}")
    private String qaPageUrl;
    @Value("${cc.community.expPageUrl}")
    private String expPageUrl;
    @Value("${cc.community.videoPageUrl}")
    private String videoPageUrl;

    public CCAgentRecommendResponseVO agentRecommend(Long pathId) {

        String code = DictCodeEnum.CC_AGENT_RECOMMEND_CONFIG.getCode();
        code = String.format(code, pathId);
        List<DictConfigResponseVO> dicts = dictConfigService.getDictConfigVOListFromCache(code);
        if (CollectionUtils.isEmpty(dicts)) {
            throw new BusinessException("未查询到Agent推荐配置");
        }
        String recommendTitle = "";
        Set<String> recommendQuestions = new HashSet<>();
        for (DictConfigResponseVO dict : dicts) {
            if (DictNameEnum.CC_AGENT_RECOMMEND_TITLE.getName().equals(dict.getName())) {
                recommendTitle = dict.getValue();
            } else if (DictNameEnum.CC_AGENT_RECOMMEND_QUESTION.getName().equals(dict.getName())) {
                recommendQuestions.add(dict.getValue());
            }
        }
        if (CollectionUtils.isNotEmpty(recommendQuestions)) {
            List<String> questions = new ArrayList<>(recommendQuestions);
            ListUtil.shuffle(questions);
            recommendQuestions = new HashSet<>(questions.subList(0, Math.min(4, recommendQuestions.size())));
        }
        CCAgentRecommendResponseVO agentRecommendResponse = new CCAgentRecommendResponseVO();
        agentRecommendResponse.setRecommendTitle(recommendTitle);
        agentRecommendResponse.setRecommendQuestions(recommendQuestions);
        return agentRecommendResponse;
    }


    public void chat(String userId, CCLLMChatRequestDTO requestDTO) {
        SseEmitter sseEmitter = SseEmitterHelper.get(requestDTO.getBiz(), userId);
        if (sseEmitter == null) {
            return;
        }
        Long pathId = requestDTO.getPathId();
        AbstractResourceBehaviorService attendService =
                ResourceBehaviorFactory.getBehaviorService(ResourceBehaviorTypeEnum.FOCUS.getBehavior());
        Map<Long, Boolean> isAttendMap = attendService.getIsBehaviorFromCache(ResourceTypeEnum.CTC_PATH.getType(), Arrays.asList(pathId), userId);
        if (!isAttendMap.getOrDefault(pathId, false)) {
            try {
                sseEmitter.send("无权限(请先订阅社区)");
                sseEmitter.send("finished");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return;
        }
        CTCPathDetailVO pathDetailVO = pathService.getPathBaseFromCache(requestDTO.getPathId());
        if (pathDetailVO == null) {
            try {
                sseEmitter.send("未找到社区信息");
                sseEmitter.send("finished");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return;
        }
        CommunitySearchResultDTO searchResult = queryDocumentsFormES(requestDTO.getPathId(), requestDTO.getMessage());
        String document = "-";
        if (searchResult != null && searchResult.getData() != null) {
            CommunityEventData data = searchResult.getData();
            try {
                String resourceUrl = getResourceUrl(data.getType(), data.getBizId());
                if (StringUtils.isNotBlank(resourceUrl)) {
                    sseEmitter.send("<a href=\""+resourceUrl+"\" target=\"_blank\"><button class='refDocument'><i class=\"layui-icon\">&#xe602;</i>社区资料源："+searchResult.getData().getTitle()+"</button><br/></a>");
                }
            } catch (IOException e) {}
            document = JsonUtil.toJsonString(data);
        }
        Map<String, Object> vars = new HashMap<>();
        vars.put("ccName", JsonUtil.toJsonString(pathDetailVO.getName()));
        vars.put("input", requestDTO.getMessage());
        vars.put("document", document);
        try {
            String prompt = freeMarkEngineService.getContentByTemplate(PromptTemplateEnum.COMMUNITY_RAG.getName(), vars);
            final List<ChatCompletionMessage> messageList = Arrays.asList(
                    new ChatCompletionMessage(ChatMessageRole.SYSTEM.value(), String.format("你是《%s》的智能问答助理！", pathDetailVO.getName())),
                    new ChatCompletionMessage(ChatMessageRole.USER.value(), prompt));
            deepSeekAIService.chat(sseEmitter, messageList);
        } catch (Exception e) {
            log.error("知识社区RAG问答处理异常====> 参数={}", JsonUtil.toJsonString(requestDTO), e);
        }
    }

    public void chatByWebSocket(String userId, CCLLMChatRequestDTO requestDTO) {
        if (!AibotSocket.isConnected(userId)) {
            return;
        }
        Long pathId = requestDTO.getPathId();
        AbstractResourceBehaviorService attendService =
                ResourceBehaviorFactory.getBehaviorService(ResourceBehaviorTypeEnum.FOCUS.getBehavior());
        Map<Long, Boolean> isAttendMap = attendService.getIsBehaviorFromCache(ResourceTypeEnum.CTC_PATH.getType(), Arrays.asList(pathId), userId);
        if (!isAttendMap.getOrDefault(pathId, false)) {
            try {
                AibotSocket.doSend(userId, "无权限(请先订阅社区)");
                AibotSocket.doSend(userId,"finished");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return;
        }
        CTCPathDetailVO pathDetailVO = pathService.getPathBaseFromCache(requestDTO.getPathId());
        if (pathDetailVO == null) {
            try {
                AibotSocket.doSend(userId, "未找到社区信息");
                AibotSocket.doSend(userId,"finished");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return;
        }
        CommunitySearchResultDTO searchResult = queryDocumentsFormES(requestDTO.getPathId(), requestDTO.getMessage());
        String document = "-";
        if (searchResult != null && searchResult.getData() != null) {
            CommunityEventData data = searchResult.getData();
            try {
                if (data.getType() != null) {
                    Integer resType = data.getType();
                    Long resId = getResourceId(resType, data.getBizId());
                    String resTitle = searchResult.getData().getTitle();
                    AibotSocket.doSend(userId, "resId="+resId);
                    AibotSocket.doSend(userId, "resType="+resType);
                    AibotSocket.doSend(userId, "resTitle="+resTitle);
                }
            } catch (Exception e) {}
            document = JsonUtil.toJsonString(data);
        }
        Map<String, Object> vars = new HashMap<>();
        vars.put("ccName", JsonUtil.toJsonString(pathDetailVO.getName()));
        vars.put("input", requestDTO.getMessage());
        vars.put("document", document);
        try {
            String prompt = freeMarkEngineService.getContentByTemplate(PromptTemplateEnum.COMMUNITY_RAG.getName(), vars);
            final List<ChatCompletionMessage> messageList = Arrays.asList(
                    new ChatCompletionMessage(ChatMessageRole.SYSTEM.value(), String.format("你是《%s》的智能问答助理！", pathDetailVO.getName())),
                    new ChatCompletionMessage(ChatMessageRole.USER.value(), prompt));
            deepSeekAIService.chatByWebSocket(userId, messageList);
        } catch (Exception e) {
            log.error("知识社区RAG问答处理异常====> 参数={}", JsonUtil.toJsonString(requestDTO), e);
        }
    }

    public Flux<String> chatStream(String userId, CCLLMChatRequestDTO requestDTO) {
        if (StringUtils.isEmpty(userId)) {
            return Flux.just("未登录", "finished");
        }
        Long pathId = requestDTO.getPathId();
        AbstractResourceBehaviorService attendService =
                ResourceBehaviorFactory.getBehaviorService(ResourceBehaviorTypeEnum.FOCUS.getBehavior());
        Map<Long, Boolean> isAttendMap = attendService.getIsBehaviorFromCache(ResourceTypeEnum.CTC_PATH.getType(), Arrays.asList(pathId), userId);
        if (!isAttendMap.getOrDefault(pathId, false)) {
            return Flux.just("无权限(请先订阅社区)", "finished");
        }
        CTCPathDetailVO pathDetailVO = pathService.getPathBaseFromCache(requestDTO.getPathId());
        if (pathDetailVO == null) {
            return Flux.just("未找到社区信息", "finished");
        }

        Flux<String> resourceFlux = Flux.empty();
        CommunitySearchResultDTO searchResult = queryDocumentsFormES(requestDTO.getPathId(), requestDTO.getMessage());
        String document = "-";
        if (searchResult != null && searchResult.getData() != null) {
            CommunityEventData data = searchResult.getData();
            String resourceUrl = getResourceWxAppUrl(data.getType(), data.getBizId());
            if (StringUtils.isNotBlank(resourceUrl)) {
                String linkHtml = "<navigator url=\""+resourceUrl+"\"><button class=\"login-btn\"> 社区资料源："+searchResult.getData().getTitle()+" </button></navigator>";
                resourceFlux = Flux.just(linkHtml);
            }
            document = JsonUtil.toJsonString(data);
        }
        Map<String, Object> vars = new HashMap<>();
        vars.put("ccName", JsonUtil.toJsonString(pathDetailVO.getName()));
        vars.put("input", requestDTO.getMessage());
        vars.put("document", document);
        try {
            String prompt = freeMarkEngineService.getContentByTemplate(PromptTemplateEnum.COMMUNITY_RAG.getName(), vars);
            final List<ChatCompletionMessage> messageList = Arrays.asList(
                    new ChatCompletionMessage(ChatMessageRole.SYSTEM.value(), String.format("你是《%s》的智能问答助理！", pathDetailVO.getName())),
                    new ChatCompletionMessage(ChatMessageRole.USER.value(), prompt));
            // 先返回资源链接，再返回模型对话
//            return Flux.concat(
//                    resourceFlux,
//                    deepSeekAIService.chatByStreamV3(messageList)
//            );
            return deepSeekAIService.chatByStreamV3(messageList);
        } catch (Exception e) {
            log.error("知识社区RAG问答处理异常====> 参数={}", JsonUtil.toJsonString(requestDTO), e);
        }
        return Flux.just("服务端繁忙", "finished");
    }

    private CommunitySearchResultDTO queryDocumentsFormES(Long pathId, String q) {
       PAIPageResponseBeanUtil<CommunitySearchResultDTO> PAIPageResponseBeanUtil = communityElasticSearchService.query(pathId, q, 1, 1);
        List<CommunitySearchResultDTO> dataList =PAIPageResponseBeanUtil.getData();
        return CollectionUtils.isEmpty(dataList) ? null : dataList.get(0);
    }

    private String getResourceUrl(int type, Long id) {
        if (CommunityDataTypeEnum.QA.getType().equals(type)) {
            CCAnswerEntity answer = answerService.getAnswerById(id);
            if (answer == null) {
                return null;
            }
            return String.format(qaPageUrl, answer.getQuestionId());
        } else if (CommunityDataTypeEnum.EXP.getType().equals(type)) {
            return String.format(expPageUrl, id);
        } else if (CommunityDataTypeEnum.VIDEO.getType().equals(type)) {
            return String.format(videoPageUrl, id);
        }
        return null;
    }

    private String getResourceWxAppUrl(int type, Long id) {
        if (CommunityDataTypeEnum.QA.getType().equals(type)) {
            CCAnswerEntity answer = answerService.getAnswerById(id);
            if (answer == null) {
                return null;
            }
            return String.format("/page/question/detail?id=", answer.getQuestionId());
        } else if (CommunityDataTypeEnum.EXP.getType().equals(type)) {
            return String.format("/page/article/detail?id=", id);
        } else if (CommunityDataTypeEnum.VIDEO.getType().equals(type)) {
            return String.format("/page/video/detail?id=", id);
        }
        return null;
    }

    private Long getResourceId(int type, Long id) {
        if (CommunityDataTypeEnum.QA.getType().equals(type)) {
            CCAnswerEntity answer = answerService.getAnswerById(id);
            if (answer == null) {
                return null;
            }
        }
        return null;
    }
}
